"""
OpenAPI文档解析器
支持解析OpenAPI 3.0规范的JSON和YAML格式文档
支持本地文件和远程URL两种方式加载
"""

import json
import yaml
import requests
from typing import Dict, Any, Optional
from pathlib import Path


class OpenAPIParser:
    """OpenAPI文档解析器"""
    
    def __init__(self):
        self.spec = None
        
    def load_from_file(self, file_path: str) -> Dict[str, Any]:
        """
        从本地文件加载OpenAPI规范
        
        Args:
            file_path: 文件路径，支持.json/.yaml/.yml格式
            
        Returns:
            解析后的OpenAPI规范字典
            
        Raises:
            FileNotFoundError: 文件不存在
            ValueError: 文件格式错误
        """
        path = Path(file_path)
        
        if not path.exists():
            raise FileNotFoundError(f"文件不存在: {file_path}")
        
        try:
            with open(path, 'r', encoding='utf-8') as f:
                if path.suffix in ['.yaml', '.yml']:
                    self.spec = yaml.safe_load(f)
                elif path.suffix == '.json':
                    self.spec = json.load(f)
                else:
                    raise ValueError(f"不支持的文件格式: {path.suffix}")
                    
            self._validate_spec()
            return self.spec
            
        except yaml.YAMLError as e:
            raise ValueError(f"YAML格式错误: {str(e)}")
        except json.JSONDecodeError as e:
            raise ValueError(f"JSON格式错误: {str(e)}")
    
    def load_from_url(self, url: str, timeout: int = 10) -> Dict[str, Any]:
        """
        从远程URL加载OpenAPI规范
        
        Args:
            url: OpenAPI文档的URL地址
            timeout: 请求超时时间（秒）
            
        Returns:
            解析后的OpenAPI规范字典
            
        Raises:
            requests.RequestException: 网络请求失败
            ValueError: 文档格式错误
        """
        try:
            response = requests.get(url, timeout=timeout)
            response.raise_for_status()
            
            # 根据Content-Type判断格式
            content_type = response.headers.get('Content-Type', '')
            
            if 'yaml' in content_type or url.endswith(('.yaml', '.yml')):
                self.spec = yaml.safe_load(response.text)
            else:
                self.spec = response.json()
                
            self._validate_spec()
            return self.spec
            
        except requests.Timeout:
            raise requests.RequestException(f"请求超时: {url}")
        except requests.RequestException as e:
            raise requests.RequestException(f"请求失败: {str(e)}")
        except (yaml.YAMLError, json.JSONDecodeError) as e:
            raise ValueError(f"文档格式错误: {str(e)}")
    
    def _validate_spec(self):
        """验证OpenAPI规范的基本结构"""
        if not isinstance(self.spec, dict):
            raise ValueError("OpenAPI规范必须是字典格式")
        
        if 'openapi' not in self.spec and 'swagger' not in self.spec:
            raise ValueError("无效的OpenAPI规范：缺少版本信息")
        
        if 'paths' not in self.spec:
            raise ValueError("无效的OpenAPI规范：缺少paths字段")
    
    def get_paths(self) -> Dict[str, Any]:
        """获取所有API路径"""
        if not self.spec:
            raise ValueError("请先加载OpenAPI规范")
        return self.spec.get('paths', {})
    
    def get_base_url(self) -> Optional[str]:
        """获取基础URL"""
        if not self.spec:
            return None
        
        # OpenAPI 3.0
        servers = self.spec.get('servers', [])
        if servers and len(servers) > 0:
            return servers[0].get('url', '')
        
        # Swagger 2.0
        schemes = self.spec.get('schemes', ['http'])
        host = self.spec.get('host', '')
        base_path = self.spec.get('basePath', '')
        
        if host:
            return f"{schemes[0]}://{host}{base_path}"
        
        return None
    
    def get_info(self) -> Dict[str, Any]:
        """获取API信息"""
        if not self.spec:
            return {}
        return self.spec.get('info', {})
    
    def generate_example_value(self, schema: Dict[str, Any]) -> Any:
        """
        根据JSON Schema生成示例值
        
        Args:
            schema: JSON Schema定义
            
        Returns:
            生成的示例值
        """
        if not schema:
            return None
        
        # 如果有example字段，直接使用
        if 'example' in schema:
            return schema['example']
        
        # 如果有default字段，使用默认值
        if 'default' in schema:
            return schema['default']
        
        # 如果有enum字段，使用第一个枚举值
        if 'enum' in schema and schema['enum']:
            return schema['enum'][0]
        
        # 根据类型生成示例值
        schema_type = schema.get('type', 'string')
        
        if schema_type == 'string':
            # 检查format
            format_type = schema.get('format', '')
            if format_type == 'date':
                return '2024-01-01'
            elif format_type == 'date-time':
                return '2024-01-01T00:00:00Z'
            elif format_type == 'email':
                return 'example@example.com'
            elif format_type == 'uri':
                return 'https://example.com'
            else:
                return 'string_example'
        
        elif schema_type == 'integer':
            return 0
        
        elif schema_type == 'number':
            return 0.0
        
        elif schema_type == 'boolean':
            return True
        
        elif schema_type == 'array':
            items_schema = schema.get('items', {})
            return [self.generate_example_value(items_schema)]
        
        elif schema_type == 'object':
            properties = schema.get('properties', {})
            result = {}
            for prop_name, prop_schema in properties.items():
                result[prop_name] = self.generate_example_value(prop_schema)
            return result
        
        return None
